#include <cstdio>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>

using namespace std;

#define GRAPGVIZ_LIMIT 497

const char* head = "digraph g {\n\
graph [\n\
	rankdir = \"LR\"\n\
];\n\
node [\n\
	shape = \"plaintext\"\n\
		fontsize = \"8\"\n\
		fontname = \"Microsoft Sans Serif,Sans\"\n\
];\n\
edge [\n\
	arrowsize = \"0.5\"\n\
		fontsize = \"8\"\n\
		fontname = \"Microsoft Sans Serif,Sans\"\n\
];\n";

const char* nodeTempl = "\"node%d\" [\n\
label = <<TABLE BORDER=\"0\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\">\n\
	<TR>\n\
		<TD PORT=\"f0\" WIDTH=\"20\">\n\
			#%d:%d*%.1f\n\
		</TD>\n\
	</TR>\n\
	<TR>\n\
		<TD PORT=\"f1\" BORDER=\"1\" TITLE=\"%s\" HREF=\"\">\n\
			%s...%s\n\
		</TD>\n\
	</TR>\n\
</TABLE>>\n\
];\n";

const char* edgeTempl = "\"node%d\":f1:e -> \"node%d\":f1:w [\n\
	label = \"%d\"\n\
];\n";

const char* endDot = "}";

struct Node {
	int id;
	int length;
	float coverage;
	string content;
};

struct Edge {
	int start;
	int end;
	int multiplicity;
};

bool writeDot(vector<Node>& nodes, vector<Edge>& edges, const string& filename)
{
	FILE* dotfile = fopen(filename.c_str(), "w");
	if (!dotfile) {
		return false;
	}
	if (!fprintf(dotfile, head))
	{
		fclose(dotfile);
		return false;
	}
	for (int i = 0; i < nodes.size(); ++i) {
		if (!fprintf(dotfile, nodeTempl, nodes[i].id, nodes[i].id, nodes[i].length, nodes[i].coverage,
			nodes[i].content.substr(0, GRAPGVIZ_LIMIT).c_str(), nodes[i].content.substr(0, 4).c_str(),
			nodes[i].content.substr(nodes[i].content.size()-4, 4).c_str())) {
			fclose(dotfile);
			return false;
		}
	}
	for (int i = 0; i < edges.size(); ++i) {
		if (!fprintf(dotfile, edgeTempl, edges[i].start, edges[i].end, edges[i].multiplicity)) {
			fclose(dotfile);
			return false;
		}
	}
	if (!fprintf(dotfile, endDot)) {
		fclose(dotfile);
		return false;
	}
	return !fclose(dotfile);
}

bool readNodes(vector<Node>& nodes, const string& filename)
{
	ifstream nodefile(filename.c_str());
	if (!nodefile) {
		return false;
	}
	while (nodefile) {
		Node node;
		nodefile >> node.id >> node.length >> node.coverage >> node.content;
		if (nodefile) { // equivalent to !nodefile.fail()
			nodes.push_back(node);
		}
	}
	nodefile.close();
	return true;
}

bool readEdges(vector<Edge>& edges, const string& filename)
{
	ifstream edgefile(filename.c_str());
	if (!edgefile) {
		return false;
	}
	while (edgefile) {
		Edge edge;
		edgefile >> edge.start >> edge.end >> edge.multiplicity;
		if (edgefile) { // equivalent to !nodefile.fail()
			edges.push_back(edge);
		}
	}
	edgefile.close();
	return true;
}

int main(int argc, char* argv[])
{
	if (argc != 4) {
		cout <<"Usage: " << argv[0] << " node_file edge_file dot_file" << endl;
		return -1;
	}
	vector<Node> nodes;
	vector<Edge> edges;
	if (!readNodes(nodes, argv[1])) {
		cerr << "read nodes failed\n";
	}
	if (!readEdges(edges, argv[2])) {
		cerr << "read edges failed\n";
	}
	if (!writeDot(nodes, edges, argv[3])) {
		cerr << "write dot failed\n";
	} else {
		cout << "write dot succeeded\n";
	}
}